/**
 * \brief  Core implementation of the CPU session/thread interfaces
 * \author Christian Helmuth
 * \date   2006-07-17
 *
 * FIXME arg_string and quota missing
 */

/*
 * Copyright (C) 2006-2009 Christian Helmuth
 * Genode Labs, Feske & Helmuth Systementwicklung GbR
 *
 * This file is part of the Genode OS framework, which is distributed
 * under the terms of the GNU General Public License version 2.
 */

/* Genode */
#include <base/printf.h>

/* Core */
#include <cpu_session_component.h>

using namespace Genode;


Thread_capability Cpu_session_component::create_thread(const char *name)
{
	Lock::Guard thread_list_lock_guard(_thread_list_lock);
	Lock::Guard slab_lock_guard(_slab_lock);

	Cpu_thread *thread = 0;
	try {
		thread = new(&_slab) Cpu_thread(name);
	} catch (Allocator::Out_of_memory) {
		throw Thread_creation_failed();
	}

	_thread_list.insert(thread);
	return Thread_capability(_thread_ep->manage(thread));
}


void Cpu_session_component::_unsynchronized_kill_thread(Cpu_thread *thread)
{
	Lock::Guard lock_guard(_slab_lock);

	_thread_ep->dissolve(thread);
	_thread_list.remove(thread);

	destroy(&_slab, thread);
}


void Cpu_session_component::kill_thread(Thread_capability thread_cap)
{
	Lock::Guard lock_guard(_thread_list_lock);

	Cpu_thread *thread = _lookup_thread(thread_cap);
	if (!thread) return;

	_unsynchronized_kill_thread(thread);
}


Thread_capability Cpu_session_component::first()
{
	Lock::Guard lock_guard(_thread_list_lock);

	return _thread_list.first() ? Thread_capability(_thread_list.first()->cap())
	                            : Thread_capability();
}


Thread_capability Cpu_session_component::next(Thread_capability thread_cap)
{
	Lock::Guard lock_guard(_thread_list_lock);

	Cpu_thread *thread = _lookup_thread(thread_cap);

	if (!thread || !thread->next())
		return Thread_capability();

	return Thread_capability(thread->next()->cap());
}


int Cpu_session_component::set_pager(Thread_capability thread_cap,
                                     Thread_capability pager_cap)
{
	Cpu_thread *thread = _lookup_thread(thread_cap);
	if (!thread) return -1;

	thread->platform_thread()->pager_cap(pager_cap);
	return 0;
}


int Cpu_session_component::start(Thread_capability thread_cap,
                                 addr_t ip, addr_t sp)
{
	Cpu_thread *thread = _lookup_thread(thread_cap);
	if (!thread) return -1;

	thread->platform_thread()->start((void *)ip, (void *)sp);
	return 0;
}


void Cpu_session_component::cancel_blocking(Thread_capability thread_cap)
{
	Cpu_thread *thread = _lookup_thread(thread_cap);

	if (thread)
		thread->platform_thread()->cancel_blocking();
}


int Cpu_session_component::name(Thread_capability thread_cap,
                                char *name_dst, size_t name_len)
{
	Cpu_thread *thread = _lookup_thread(thread_cap);
	if (!thread) return -1;

	strncpy(name_dst, thread->platform_thread()->name(), name_len);
	return 0;
}


int Cpu_session_component::state(Thread_capability thread_cap,
                                 Thread_state *state_dst)
{
	Cpu_thread *thread = _lookup_thread(thread_cap);
	if (!thread) return -1;

	thread->platform_thread()->state(state_dst);
	return 0;
}


Cpu_session_component::~Cpu_session_component()
{
	Lock::Guard lock_guard(_thread_list_lock);

	/*
	 * We have to keep the '_thread_list_lock' during the whole destructor to
	 * prevent races with incoming calls of the 'create_thread' function,
	 * adding new threads while we are destroying them.
	 */

	for (Cpu_thread *thread; (thread = _thread_list.first()); )
		_unsynchronized_kill_thread(thread);
}
